package com.dongzili.demo.common.utils;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.toolkit.LambdaUtils;
import com.baomidou.mybatisplus.core.toolkit.support.LambdaMeta;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.property.PropertyNamer;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
public class QueryUtils {


    @SafeVarargs
    public static <T> String buildFullTextSearchSql(String keyword, SFunction<T, ?>... columns) {
        if(!StringUtils.hasText(keyword)){
            throw new IllegalArgumentException("查询关键词不能为空");
        }
        List<String> fields = getColumns(columns);
        List<String> parts = new ArrayList<>(Arrays.asList(keyword.split(" ")));  //IKAnalyzerSupport.iKSegmenterToList(keyword);
//        parts = parts.stream().map(part->"+"+part).collect(Collectors.toList());
//        String text = String.join(" ", parts);
//        text = "'"+text+"'";

        if (parts.isEmpty()){
            parts.add(keyword);
        }
        String firstKeyword = "'"+parts.stream().findFirst().get()+"'";
        parts.remove(0);
        String otherLikeText = "";
        if(!parts.isEmpty()){
            otherLikeText = generateConditionSQL(fields, parts);
//            otherLikeText.append(fields.stream().map(field->
//                    parts.stream().map(part->
//                            field+" like '%"+part+"%'").collect(Collectors.joining(" and ")
//                    )
//            ).collect(Collectors.joining(" or ")));

        }
        // 生成 SQL 语句，支持多个字段
        String fieldsJoined = String.join(",", fields);

        return MessageFormat.format("MATCH({0}) AGAINST ({1} IN BOOLEAN MODE) {2}", fieldsJoined, firstKeyword, otherLikeText);
//        return MessageFormat.format("MATCH({0}) AGAINST ({1} IN NATURAL LANGUAGE MODE)", fieldsJoined, sanitizedKeyword);
//        return String.format("MATCH(%s) AGAINST ('%s' IN NATURAL LANGUAGE MODE)", fieldsJoined, sanitizedKeyword);
    }
    /**
     * 获取字段名
     */
    @SafeVarargs
    public static <T> List<String> getColumns(SFunction<T, ?>... columns) {
        // 获取字段名
        return Arrays.stream(columns).map(QueryUtils::getFieldNameFromSFunction).collect(Collectors.toList());
    }

    public static String generateConditionSQL(List<String> fields, List<String> parts){
        StringBuilder otherLikeText = new StringBuilder();
        otherLikeText.append(" and (");

        // 使用 StringJoiner 或适当的处理避免末尾多余的连接符
        for (int i = 0; i < fields.size(); i++) {
            if (i > 0) {
                otherLikeText.append(" or ");  // 字段之间用 "or" 连接
            }
            String field = fields.get(i);
            otherLikeText.append("(");

            for (int j = 0; j < parts.size(); j++) {
                String part = parts.get(j);

                // 每个 LIKE 子句之间用 "and" 连接
                if (j > 0) {
                    otherLikeText.append(" and ");
                }
                // 对输入的部分进行转义 (假设 part 可能包含引号等特殊字符)
//                part = part.replace("'", "''");

                otherLikeText.append(field).append(" like '%").append(part).append("%'");
            }

            otherLikeText.append(")");
        }

        otherLikeText.append(")");
        return otherLikeText.toString();
    }

    private static <T> String getFieldNameFromSFunction(SFunction<T, ?> function) {
        // 提取 Lambda 元数据
        LambdaMeta meta = LambdaUtils.extract(function);
        String fieldName = PropertyNamer.methodToProperty(meta.getImplMethodName());
        Class<?> instantiatedClass = meta.getInstantiatedClass();

        // 使用反射获取字段对象
        Field field;
        try {
            field = instantiatedClass.getDeclaredField(fieldName);  // getDeclaredField 也可以获取 private/protected 字段
        } catch (NoSuchFieldException e) {
            // 如果没有找到字段，则记录错误日志并返回字段名
            log.error("字段 '{}' 在类 '{}' 中未找到", fieldName, instantiatedClass.getName(), e);
            return fieldName; // 如果未找到字段，返回默认字段名
        }

        // 获取字段的列名注解，优先使用 TableField，然后是 TableId
        String columnName = fieldName;
        TableField tableField = field.getAnnotation(TableField.class);
        if (tableField != null) {
            columnName = tableField.value();  // 如果字段上有 TableField 注解，使用其值
        } else {
            TableId tableId = field.getAnnotation(TableId.class);
            if (tableId != null) {
                columnName = tableId.value();  // 如果字段上有 TableId 注解，使用其值
            }
        }
        if(!StringUtils.hasText(columnName)){
            columnName = fieldName;
        }
        return columnName;  // 返回列名（可能是默认字段名，也可能是通过注解指定的列名）
    }

    /**
     * 清洗关键词，防止 SQL 注入等问题。
     */
    private static String sanitizeKeyword(String keyword) {
        if (keyword == null || keyword.trim().isEmpty()) {
            throw new IllegalArgumentException("关键词不能为空");
        }

        // 去除前后空格
        String sanitized = keyword.trim();

        // 替换掉一些潜在的恶意字符（简单示例，可以根据实际需求扩展）
//        sanitized = sanitized.replaceAll("['\";]", "");

        // 限制最大长度
        if (sanitized.length() > 255) {
            sanitized = sanitized.substring(0, 255);
        }

        return sanitized;
    }


}
